package com.ehotting.edsta.circuitDesign.service.impl;

import java.io.InputStream;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ehotting.eaf.core.domain.R;
import com.ehotting.eaf.redis.service.RedisService;
import com.ehotting.eaf.security.service.TokenService;
import com.ehotting.edsta.circuitDesign.bean.AllMapBean;
import com.ehotting.edsta.circuitDesign.bean.Constant;
import com.ehotting.edsta.circuitDesign.bean.ProCodeName;
import com.ehotting.edsta.circuitDesign.domain.*;
import com.ehotting.edsta.circuitDesign.enums.*;
import com.ehotting.edsta.circuitDesign.gen.PropertyFilterHelper;
import com.ehotting.edsta.circuitDesign.gen.element.ElementScriptEngine;
import com.ehotting.edsta.circuitDesign.gen.element.bean.ExecuteResultBean;
import com.ehotting.edsta.circuitDesign.service.*;


import com.ehotting.eaf.core.utils.StringUtils;
import io.minio.ListObjectsArgs;
import io.minio.MinioClient;
import io.minio.Result;
import io.minio.messages.Item;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ehotting.edsta.circuitDesign.mapper.EsCircuitMapper;
import org.springframework.web.multipart.MultipartFile;

/**
 * 应用场景Service业务层处理
 *
 * @author edsta
 * @date 2023-05-05
 */
@Service
public class EsCircuitServiceImpl implements IEsCircuitService {
    @Autowired
    private EsCircuitMapper esCircuitMapper;
    @Autowired
    private IEsCircuitCodeDataTemplateService esCircuitCodeDataTemplateService;
    @Autowired
    private ElementScriptEngine elementScriptEngine;
    @Autowired
    private IEsCircuitCodeDataService esCircuitCodeDataService;
    @Autowired
    private IEsCircuitTypeService iEsCircuitTypeService;
    @Autowired
    private PropertyFilterHelper propertyFilterHelper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private RedisService redisService;

    @Value("${minio.addr}")
    private String minioAddr;

    @Value("${minio.account}")
    private String minioAccount;

    @Value("${minio.pwd}")
    private String minioPwd;

    @Value("${circuitFilesBucketName}")
    private String bucketName;

    private static Logger logger = LoggerFactory.getLogger(EsCircuitServiceImpl.class);

    /**
     * 查询应用场景
     */
    @Override
    public EsCircuit selectEsCircuitById(Long id) {
        return esCircuitMapper.selectEsCircuitById(id);
    }

    /**
     * 查询应用场景列表
     */
    @Override
    public List<EsCircuit> selectEsCircuitList(EsCircuit esCircuit) {
        return esCircuitMapper.selectEsCircuitList(esCircuit);
    }
    /**
     * 新增应用场景
     */
    @Override
    public int insertEsCircuit(EsCircuit esCircuit) {
        EsCircuit isEsCircuit = esCircuitMapper.selectEsCircuitByName(esCircuit.getName());
        if (isEsCircuit != null) {
            esCircuit.setId(isEsCircuit.getId());
            return updateEsCircuit(esCircuit);
        }
        // todo 部署要放开
        //esCircuit.setUserId(tokenService.getLoginUser().getSysUser().getUserId());
        esCircuit.setUserId(1L);
        return esCircuitMapper.insertEsCircuit(esCircuit);
    }

    @Override
    public void insertEsCircuits(List<EsCircuit> esCircuits) {
        List<EsCircuit> esCircuitList = esCircuitMapper.selectEsCircuitList(null);
        HashMap<String, Long> stringLongHashMap = new HashMap<>();
        for(EsCircuit e : esCircuitList){
            stringLongHashMap.put(e.getName(),e.getId());
        }

        ArrayList<EsCircuit> insertList = new ArrayList<>();
        ArrayList<EsCircuit> updateList = new ArrayList<>();
        for (EsCircuit e : esCircuits){
            if(stringLongHashMap.get(e.getName()) != null){
                e.setId(stringLongHashMap.get(e.getName()));
                updateList.add(e);
            }else {
                insertList.add(e);
            }
        }
        // todo 部署要放开
        //esCircuit.setUserId(tokenService.getLoginUser().getSysUser().getUserId());
        //esCircuit.setUserId(1L);
        if(insertList.size()>0){
            for (EsCircuit e : insertList) {
                insertEsCircuit(e);
            }
        }
        if(updateList.size()>0){
            for (EsCircuit e : updateList){
                updateEsCircuit(e);
            }
        }
    }

    @Override
    public int batchInsert(List<EsCircuit> esCircuitList){
        return esCircuitMapper.batchInsert(esCircuitList);
    }

    /**
     * 修改应用场景
     */
    @Override
    public int updateEsCircuit(EsCircuit esCircuit) {
        return esCircuitMapper.updateEsCircuit(esCircuit);
    }

    /**
     * 批量删除应用场景
     */
    @Override
    public int deleteEsCircuitByIds(Long[] ids) {
        esCircuitCodeDataService.deleteEsCircuitCodeDataByCircuitIds(ids);
        return esCircuitMapper.deleteEsCircuitByIds(ids);
    }

    /**
     * 删除应用场景信息
     */
    @Override
    public int deleteEsCircuitById(Long id) {
        esCircuitCodeDataService.deleteEsCircuitCodeDataByCircuitId(id);
        return esCircuitMapper.deleteEsCircuitById(id);
    }

    @Override
    public String execute(Long circuitId, Long ruleId, Map<String, Object> params) {
        AllMapBean contextMap = new AllMapBean();
        List<Map<String, EsElement>> elementMap = elementScriptEngine.runByRuleScriptId(circuitId, ruleId, params, contextMap);

        ExecuteResultBean executeResultBean = new ExecuteResultBean();
        executeResultBean.setCode(1);
        executeResultBean.setMsg("success");
        executeResultBean.setData(elementMap);

        return JSONObject.toJSONString(executeResultBean, SerializerFeature.DisableCircularReferenceDetect);

    }

    @Override
    public List<EsCircuit> findByCircuitTypeId(Long circuitTypeId) {
        EsCircuit circuit = new EsCircuit();
        circuit.setCircuitTypeId(circuitTypeId);
        return esCircuitMapper.selectEsCircuitList(circuit);
    }

    @Override
    public List<EsCircuit> seEsCircuitByIds(Long[] ids) {
        if (ids != null && ids.length > 0){
            return esCircuitMapper.seEsCircuitByIds(ids);
        }
        return new ArrayList<>();
    }
    /**
     * 数据转对象-----------------------------------------------------------------------------------------------------
     */
    private void checkSheet0(List<List<String>> sheet0List){
        List<EsCircuit> esCircuits = new ArrayList<>();
        for(List<String> rowList : sheet0List){
            EsCircuit esCircuit = new EsCircuit();
            // 电路名称
            esCircuit.setName(rowList.get(0).replace(" ",""));
            // 电路类型
            esCircuit.setCircuitTypeId(iEsCircuitTypeService.selectCircuitTypeIdByName(rowList.get(1)));
            // 采集类型
            esCircuit.setSignalType(SignalTypeEnum.getSignalTypeEnumByName(rowList.get(2)));
            // 存储类型
            esCircuit.setStorageType(StorageTypeEnum.getStorageTypeEnumByName(rowList.get(3)));
            // 存储容量
            esCircuit.setStorageCapacity(Long.getLong(rowList.get(4)));
            // 状态
            esCircuit.setState(StateTypeEnum.YES);
            //缩略图
            esCircuit.setThumbnailPath(bucketName+"/"+urlRevise(rowList.get(6)));
            //封面图
            esCircuit.setThumbPath(bucketName+"/"+urlRevise(rowList.get(7)));
            //图表
            esCircuit.setChartsPath(bucketName+"/"+urlRevise(rowList.get(8)));
            //模板工程
            esCircuit.setProjectPath(bucketName+"/"+urlRevise(rowList.get(9)));
            //bom表
            esCircuit.setBomPath(bucketName+"/"+urlRevise(rowList.get(10)));
            //网络替换表
            esCircuit.setNetPath(rowList.size()>11 ? bucketName+"/"+urlRevise(rowList.get(11)) : "");
            //位号替换表
            esCircuit.setDesignatorsPath(rowList.size()>12 ? bucketName+"/"+urlRevise(rowList.get(12)) : "");
            esCircuits.add(esCircuit);
        }


        // 插入数据库
        double listSize = 300.0;
        int ceil = (int) Math.ceil(esCircuits.size() / listSize);
        List<List<EsCircuit>> esCircuitSs = new ArrayList<>();
        for(int c=1;c<=ceil;c++){
            int start = (int) ((c-1)*listSize);
            int end = c*listSize > esCircuits.size() ? esCircuits.size() : (int) (c * listSize);
            esCircuitSs.add(esCircuits.subList(start,end));
        }
        ExcelToMapListListThreadPool<List<EsCircuit>> esCircuitsToDB = new ExcelToMapListListThreadPool<List<EsCircuit>>() {
            @Override
            public void task(List<EsCircuit> esCircuits) {
                insertEsCircuits(esCircuits);
            }
        };
        esCircuitsToDB.execute(esCircuitSs);

    }
    private void checkSheet1(List<List<String>> sheet1List,List<EsCircuitCodeData> esCircuitCodeDataList){
        EsCircuit esCircuit = new EsCircuit();
        esCircuit.setCircuitTypeId(2L);
        List<EsCircuit> esCircuits = esCircuitMapper.selectEsCircuitList(esCircuit);
        HashMap<String, Long> stringLongHashMap = new HashMap<>();
        for(EsCircuit e : esCircuits){
            stringLongHashMap.put(e.getName(),e.getId());
        }
        // 获取数据处理电路属性模板id
        Map<String, Long> templateIds = esCircuitCodeDataTemplateService.selectByCircuitTypeIdReturnMap(2L);
        for(List<String> rowList : sheet1List){
            for (int r=1;r<rowList.size();r++){
                EsCircuitCodeData controllerCircuitCodeData = new EsCircuitCodeData();
                controllerCircuitCodeData.setCircuitId(stringLongHashMap.get(rowList.get(0)));
                controllerCircuitCodeData.setState(StateTypeEnum.YES);
                switch (r) {
                    case 1: //质量等级
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Quality_Grade));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 2: //接口类型（接口）
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Cpu_Interface));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 3: //供电电压（电压）
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Cpu_Voltage));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 4: //ADC位数
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Adc_Sampling_Bit));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 5: //采样率
                        controllerCircuitCodeData.setValue(hzConverted(rowList.get(r)));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Sample));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 6: //控制器类型
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Controller));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 7: //通道类型
                        break;
                    case 8: //内部接口类型
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Internal_Interface));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 9: //来源
                        if (rowList.get(r).contains("进口")) {
                            controllerCircuitCodeData.setValue("1");
                        } else {
                            controllerCircuitCodeData.setValue("0");
                        }
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Source));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 10: //通道数（数字）
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Digital_Channel_Num));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 11: //通道数
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Channel_Num));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 12: //存储速率
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Storage_Rate));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    case 13: //存储容量
                        controllerCircuitCodeData.setValue(rowList.get(r));
                        controllerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Storage_Capacity));
                        esCircuitCodeDataList.add(controllerCircuitCodeData);
                        break;
                    default:
                        break;
                }
            }

        }

    }
    private void checkSheet2(List<List<String>> sheet2List,List<EsCircuitCodeData> esCircuitCodeDataList){
        EsCircuit esCircuit = new EsCircuit();
        esCircuit.setCircuitTypeId(1L);
        List<EsCircuit> esCircuits = esCircuitMapper.selectEsCircuitList(esCircuit);
        HashMap<String, Long> stringLongHashMap = new HashMap<>();
        for(EsCircuit e : esCircuits){
            stringLongHashMap.put(e.getName(),e.getId());
        }
        Map<String, Long> templateIds = esCircuitCodeDataTemplateService.selectByCircuitTypeIdReturnMap(1L);
        for(List<String> rowList : sheet2List){
//            EsCircuit isEsCircuit =  esCircuitMapper.selectEsCircuitByName(rowList.get(0));
            for (int r=1;r<rowList.size();r++){
                if(StringUtils.isEmpty(rowList.get(r))) continue;
                EsCircuitCodeData sensorCircuitCodeData = new EsCircuitCodeData();
                sensorCircuitCodeData.setCircuitId(stringLongHashMap.get(rowList.get(0)));
                sensorCircuitCodeData.setState(StateTypeEnum.YES);
                switch (r){
                    case 1: //质量等级
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Quality_Grade));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 2: //供电电压
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Sensor_Voltage));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 3: //通道数
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Channel_Num));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 4: //位数（精度）
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Number_Of_Digits));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 5: //采样率
                        sensorCircuitCodeData.setValue(hzConverted(rowList.get(r)));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Sample));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 6: //输入端电压范围
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Input_Voltage_Range));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 7: //最大输入范围
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Input_Max_Range));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 8: //最小输入范围
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Input_Min_Range));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 9: //输出类型
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Output_Type));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 10: //最大频率
                        sensorCircuitCodeData.setValue(hzConverted(rowList.get(r)));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.F_Max));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 11: //最小频率
                        sensorCircuitCodeData.setValue(hzConverted(rowList.get(r)));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.F_Min));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 12: //通道类型
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Channel_Type));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 13: //控制读取方式
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Controller_Read));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 14: //器件来源
                        if (rowList.get(r).contains("进口")) {
                            sensorCircuitCodeData.setValue("1");
                        } else {
                            sensorCircuitCodeData.setValue("0");
                        }
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Source));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 15: //数字通道类型
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.In_Type));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    case 16: //芯片型号
                        sensorCircuitCodeData.setValue(rowList.get(r));
                        sensorCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Sense_Model));
                        esCircuitCodeDataList.add(sensorCircuitCodeData);
                        break;
                    default:
                        break;
                }
            }
        }
    }
    private void checkSheet3(List<List<String>> sheet3List,List<EsCircuitCodeData> esCircuitCodeDataList){
        EsCircuit esCircuit = new EsCircuit();
        esCircuit.setCircuitTypeId(3L);
        List<EsCircuit> esCircuits = esCircuitMapper.selectEsCircuitList(esCircuit);
        HashMap<String, Long> stringLongHashMap = new HashMap<>();
        for(EsCircuit e : esCircuits){
            stringLongHashMap.put(e.getName(),e.getId());
        }
        Map<String, Long> templateIds = esCircuitCodeDataTemplateService.selectByCircuitTypeIdReturnMap(3L);
        for(List<String> rowList : sheet3List){
//            EsCircuit isEsCircuit =  esCircuitMapper.selectEsCircuitByName(rowList.get(0));
            for (int r=1;r<rowList.size();r++){
                EsCircuitCodeData powerCircuitCodeData = new EsCircuitCodeData();
                powerCircuitCodeData.setCircuitId(stringLongHashMap.get(rowList.get(0)));
                powerCircuitCodeData.setState(StateTypeEnum.YES);
                switch (r){
                    case 1: //输入电压
                        powerCircuitCodeData.setValue(rowList.get(r));
                        powerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.In_Voltage));
                        esCircuitCodeDataList.add(powerCircuitCodeData);
                        break;
                    case 2: //输出电压
                        powerCircuitCodeData.setValue(rowList.get(r));
                        powerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Out_Voltage));
                        esCircuitCodeDataList.add(powerCircuitCodeData);
                        break;
                    case 3: //质量等级
                        powerCircuitCodeData.setValue(rowList.get(r));
                        powerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Quality_Grade));
                        esCircuitCodeDataList.add(powerCircuitCodeData);
                        break;
                    case 4: //最大功率
                        powerCircuitCodeData.setValue(rowList.get(r));
                        powerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Max_Power));
                        esCircuitCodeDataList.add(powerCircuitCodeData);
                        break;
                    case 5: //通道类型
                        break;
                    case 6: //来源
                        if (rowList.get(r).contains("进口")) {
                            powerCircuitCodeData.setValue("1");
                        } else {
                            powerCircuitCodeData.setValue("0");
                        }
                        powerCircuitCodeData.setTemplateId(templateIds.get(ProCodeName.Source));
                        esCircuitCodeDataList.add(powerCircuitCodeData);
                        break;
                    default:
                        break;
                }
            }
        }
    }

    /**
     * excel表数据获取
     */
    public Map<String, List<List<String>>> excelToMapListList(Workbook workbook){
        Map<String, List<List<String>>> hashMap = new HashMap<>();
        ExcelToMapListListThreadPool<Sheet> excelToMapListListThreadPool = new ExcelToMapListListThreadPool<Sheet>() {
            @Override
            public void task(Sheet sheet) {
                List<List<String>> rowList = new ArrayList<>();
                for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                    Row row = sheet.getRow(rowIndex);
                    if (row == null
                            || row.getCell(1) == null
                            || StringUtils.isEmpty(row.getCell(1).getStringCellValue())) {
                        continue;
                    }
                    List<String> cellList = new ArrayList<>();
                    for (int cellIndex = 1; cellIndex < row.getLastCellNum(); cellIndex++) {
                        Cell cell = row.getCell(cellIndex);
                        String cellValue;
                        if (cell == null) {
                            cellValue = "";
                            cellList.add(cellValue);
                            continue;
                        }
                        // 判断单元格数据类型
                        if (cell.getCellType() == CellType.NUMERIC) {
                            cellValue = String.valueOf(cell.getNumericCellValue());
                        } else {
                            cellValue = cell.getStringCellValue();
                        }
                        cellList.add(cellValue);
                    }
                    rowList.add(cellList);
                }
                hashMap.put(sheet.getSheetName(),rowList);
            }
        };
        List<Sheet> sheets = new ArrayList<>();
        sheets.add(workbook.getSheet("数据清单"));
        sheets.add(workbook.getSheet("数据处理电路"));
        sheets.add(workbook.getSheet("数据采集电路"));
        sheets.add(workbook.getSheet("电源电路"));
        excelToMapListListThreadPool.execute(sheets);
        return hashMap;
    }

    /**
     * excel表规范校验
     */
    private R checkAllSheet(Workbook workbook){
        Long userId = tokenService.getLoginUser().getUserid();
        /**
         * 工作区命名检查
         */
        if(workbook.getSheet("数据清单")==null){
            return R.okMsg("电路数据缺少[数据清单]工作表");
        }
        if(workbook.getSheet("数据处理电路")==null){
            return R.okMsg("电路数据缺少[数据处理电路]工作表");
        }
        if(workbook.getSheet("数据采集电路")==null){
            return R.okMsg("电路数据缺少[数据采集电路]工作表");
        }
        if(workbook.getSheet("电源电路")==null){
            return R.okMsg("电路数据缺少[电源电路]工作表");
        }
        logger.info("工作区命名正确√√√√√");
        Map<String, List<List<String>>> hashMap = excelToMapListList(workbook);
        /**
         * 文件完整性检查
         */
        Set<String> excelFilesUrl = new HashSet<>();
        for(List<String> rowList : hashMap.get("数据清单")){
            for(int r=7;r<rowList.size();r++){
                String replace = rowList.get(r).replace("\\", "/").replace(bucketName + "/", "");
                excelFilesUrl.add(replace);
            }
        }
        JSONArray circuitFilesNoDB = new JSONArray();
        JSONArray localFileList = redisService.getCacheObject(Constant.CIRCUIT_FILE_IMPORT_LIST+userId);
        for(String s : excelFilesUrl){
            if(!localFileList.contains(s)){
                circuitFilesNoDB.add(s);
            }
        }
        circuitFilesNoDB.remove("");
        if(circuitFilesNoDB.size() != 0){
            redisService.setCacheObject(Constant.CIRCUIT_FILES_LACK_LIST+userId, circuitFilesNoDB, 2L, TimeUnit.HOURS);
            return R.okMsg("文件缺失");
        }
        logger.info("上传文件完整√√√√√");

        /**
         * 电路模板存在性检查
         */
        List<List<String>> sheet0List = hashMap.get("数据清单");
        List<String> excelCircuitName = new ArrayList<>();
        for(List<String> rowList : sheet0List){
            excelCircuitName.add(rowList.get(0));
        }
        List<List<String>> sheet13List = new ArrayList<>();
        sheet13List.addAll(hashMap.get("数据处理电路"));
        sheet13List.addAll(hashMap.get("数据采集电路"));
        sheet13List.addAll(hashMap.get("电源电路"));
        List<String> esCircuitNoExist = new ArrayList<>();
        for(List<String> rowList : sheet13List){
            String circuitName = rowList.get(0);
            if(!excelCircuitName.contains(circuitName)){
                EsCircuit isEsCircuit = esCircuitMapper.selectEsCircuitByName(circuitName);
                if(isEsCircuit == null){
                    esCircuitNoExist.add(circuitName);
                }
            }
        }
        if(esCircuitNoExist.size() > 0){
            redisService.setCacheObject(Constant.CIRCUIT_NO_EXIST_LIST+userId, esCircuitNoExist, 2L, TimeUnit.HOURS);
            return R.okMsg("存在电路模板未被记录在数据库或本次数据清单中");
        }
        logger.info("电路模板均已被记录√√√√√");
        return R.ok();
    }

    private void dataToDB(Workbook workbook){
//        SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm:ss");
//        System.out.println("1:"+dateformat.format(System.currentTimeMillis()));

        Map<String, List<List<String>>> hashMap = excelToMapListList(workbook);
        checkSheet0(hashMap.get("数据清单"));
        List<EsCircuitCodeData> esCircuitCodeDataList = new ArrayList<>();
        checkSheet1(hashMap.get("数据处理电路"),esCircuitCodeDataList);
        checkSheet2(hashMap.get("数据采集电路"),esCircuitCodeDataList);
        checkSheet3(hashMap.get("电源电路"),esCircuitCodeDataList);

        // 插入数据库
        double listSize = 500.0;
        int ceil = (int) Math.ceil(esCircuitCodeDataList.size() / listSize);
        List<List<EsCircuitCodeData>> EsCircuitCodeDataSs = new ArrayList<>();
        for(int c=1;c<=ceil;c++){
            int start = (int) ((c-1)*listSize);
            int end = c*listSize > esCircuitCodeDataList.size() ? esCircuitCodeDataList.size() : (int) (c * listSize);
            EsCircuitCodeDataSs.add(esCircuitCodeDataList.subList(start,end));
        }
        // 插入数据库
        ExcelToMapListListThreadPool<List<EsCircuitCodeData>> codeDataToDB = new ExcelToMapListListThreadPool<List<EsCircuitCodeData>>() {
            @Override
            public void task(List<EsCircuitCodeData> c) {
                insertCodeData(c);
            }
        };
        codeDataToDB.execute(EsCircuitCodeDataSs);

    }

    /**
     * 电路数据Excel表数据校验
     */
    @Override
    public R circuitExcelDataCheck(MultipartFile file,String step){

        InputStream fis = null;
        Workbook workbook = null;
        try {
            fis = file.getInputStream();
            workbook = WorkbookFactory.create(fis);

            if(Integer.valueOf(step) == 0){
                return checkAllSheet(workbook);
            }

            if(Integer.valueOf(step) == 1){
                dataToDB(workbook);
            }

        }catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) fis.close();
                if (workbook != null) workbook.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return R.ok();
    }

    private void insertCodeData(List<EsCircuitCodeData> esCircuitCodeDatas){
        List<EsCircuitCodeData> esCircuitCodeDataList = esCircuitCodeDataService.selectEsCircuitCodeDataList(null);
        HashMap<Long, Set<Long>> longListHashMap = new HashMap<>();
        for(EsCircuitCodeData e : esCircuitCodeDataList){
            if(longListHashMap.get(e.getCircuitId()) == null){
                longListHashMap.put(e.getCircuitId(),new HashSet<>());
            }
            longListHashMap.get(e.getCircuitId()).add(e.getTemplateId());
        }

        List<EsCircuitCodeData> batchInsertList = new ArrayList<>();
        List<EsCircuitCodeData> batchUpateList = new ArrayList<>();
        for( EsCircuitCodeData e : esCircuitCodeDatas){
           if(longListHashMap.get(e.getCircuitId()) != null
                   && longListHashMap.get(e.getCircuitId()).contains(e.getTemplateId())){
               batchUpateList.add(e);
               continue;
           }
            batchInsertList.add(e);
        }
        if(batchInsertList.size() > 0){
            esCircuitCodeDataService.batchInsert(batchInsertList);
        }
        if(batchUpateList.size() > 0){
            esCircuitCodeDataService.batchUpdate(batchUpateList);
        }
    }

    private static String urlRevise(String str){
        str = str.replace("\\","/").replace("circuitdesign/","");
        if(StringUtils.isEmpty(str) || str.equals("NaN")) return "";
        Path path = Paths.get(str);
        String parent = "";
        if (path.getParent() != null) parent = path.getParent() + "/";

        String s = path.getFileName().toString();
        String fileName = s.substring(0,s.lastIndexOf('.'))
                .replace("-", "_")
                .replace("__", "_")
                .replace(".","");
        //修改后缀
        String fileSuffix = s.substring(s.lastIndexOf('.')).replace(".xlsx", ".xls");

        String newRelativePath = (parent + fileName +fileSuffix).replace("_.", ".");

        return newRelativePath;
    }

    /**
     * hz单位转换
     */
    private String hzConverted(String sample){

        String aCase = sample.toUpperCase().replace(" ", "");
        if(aCase.contains("MHZ")){
            Double integer = Double.valueOf(aCase.replace("MHZ", ""));
            return String.valueOf(integer*10000);
        } else if (aCase.contains("KHZ")) {
            Double integer = Double.valueOf(aCase.replace("KHZ", ""));
            return String.valueOf(integer*1000);
        }else if(aCase.contains("HZ")){
            return aCase.replace("HZ","");
        }
        return sample;
    }

    public void loadProp(EsCircuit esCircuit) {
        List<EsCircuitCodeData> circuitCodeDataList = esCircuitCodeDataService.findByCircuitId(esCircuit.getId());
        for (EsCircuitCodeData circuitCodeData : circuitCodeDataList) {
            esCircuit.getProp().put(circuitCodeData.getCircuitCodeDataTemplate().getCode(), circuitCodeData.getValue());
        }
    }

    @Override
    public List<Long> findIdsByTypeId(Long circuitTypeId) {

        return esCircuitMapper.findIdsByTypeId(circuitTypeId);
    }

    @Override
    public void loadProperty() {
        propertyFilterHelper.loadAllProperty4DB();
    }

    @Override
    public boolean filesVerify(JSONArray jsonArray){
        Long userId = tokenService.getLoginUser().getUserid();
        ArrayList<String> stringArrayList = new ArrayList<>();
        for (Object os : jsonArray){
//            Path path = Paths.get(os.toString());
//            String parent = "";
//            if(path.getParent() != null){
//                parent = path.getParent().toString().replace("\\","/");
//            }
//            String s = path.getFileName().toString();
//            String fileName = s.substring(0,s.lastIndexOf('.'))
//                    .replace("-", "_")
//                    .replace("__", "_")
//                    .replace(".","");
//            //修改后缀
//            String fileSuffix = s.substring(s.lastIndexOf('.'))
//                    .replace(".xlsx", ".xls");
//
//            String newRelativePath = (parent +"/"+ fileName +fileSuffix).replace("_.", ".");
            String newRelativePath = os.toString().replace("\\","/");
            stringArrayList.add(newRelativePath);
        }
        redisService.setCacheObject(Constant.CIRCUIT_FILE_IMPORT_LIST+userId, stringArrayList, 4L, TimeUnit.HOURS);
        return true;
    }

    @Override
    public Map<String, Object> getFileLackList(int page){
        Long userId = tokenService.getLoginUser().getUserid();
        JSONArray lackList = redisService.getCacheObject(Constant.CIRCUIT_FILES_LACK_LIST+userId);
        Map<String, Object> rMap = new HashMap<>();
        rMap.put("page",page);
        if(lackList==null){
            rMap.put("total",0);
            rMap.put("jsonArray",new JSONArray());
            return rMap;
        }
        int total = (int) Math.ceil(lackList.size() / 100.0);
        int end = page * 100 > lackList.size() ? lackList.size() : page * 100;
        String jsonString = JSON.toJSONString(lackList.subList((page - 1) * 100, end));
        JSONArray jsonArray = JSONArray.parseArray(jsonString);
        rMap.put("total",total);
        rMap.put("jsonArray",jsonArray);
        return rMap;
    }

    @Override
    public JSONArray fileLackListDownload(){
        Long userId = tokenService.getLoginUser().getUserid();
        JSONArray lackList = redisService.getCacheObject(Constant.CIRCUIT_FILES_LACK_LIST+userId);
        return lackList;
    }

    @Override
    public Map<String, Object> getNoExistList(int page){
        Long userId = tokenService.getLoginUser().getUserid();
        JSONArray lackList = redisService.getCacheObject(Constant.CIRCUIT_NO_EXIST_LIST+userId);
        Map<String, Object> hashMap = new HashMap<>();
        if(lackList==null){
            hashMap.put("total",0);
            hashMap.put("page",page);
            hashMap.put("jsonArray",new JSONArray());
            return hashMap;
        }
        int lackListSize = lackList.size();
        int total = (int) Math.ceil(lackListSize / 100.0);
        int end = page * 100 > lackListSize ? lackListSize : page * 100;
        String jsonString = JSON.toJSONString(lackList.subList((page - 1) * 100, end));
        JSONArray jsonArray = JSONArray.parseArray(jsonString);
        hashMap.put("total",total);
        hashMap.put("page",page);
        hashMap.put("jsonArray",jsonArray);
        return hashMap;
    }

    @Override
    public JSONArray NoExistListDownload(){
        Long userId = tokenService.getLoginUser().getUserid();
        JSONArray lackList = redisService.getCacheObject(Constant.CIRCUIT_NO_EXIST_LIST+userId);
        return lackList;
    }

    @Override
    public JSONArray checkDocumentLibrary(){
        MinioClient minioClient = MinioClient.builder()
                .endpoint(minioAddr)
                .credentials(minioAccount, minioPwd)
                .build();
        Iterable<Result<Item>> bucketList = minioClient.listObjects(ListObjectsArgs.builder()
                .bucket(bucketName)
                .build());
        Set<String> hashSet = new HashSet<>();
        for(Result<Item> b : bucketList){
            getBucketFliesPath(minioClient,b,bucketName,hashSet);
        }

        HashSet<String> filSet = new HashSet<>();
        List<EsCircuit> esCircuitList = esCircuitMapper.selectEsCircuitList(null);
        for(EsCircuit e : esCircuitList){
            if(!hashSet.contains(e.getProjectPath())){
                filSet.add(e.getProjectPath());
            }
            if(!hashSet.contains(e.getThumbnailPath())){
                filSet.add(e.getThumbnailPath());
            }
            if(!hashSet.contains(e.getThumbPath())){
                filSet.add(e.getThumbPath());
            }
            if(!hashSet.contains(e.getChartsPath())){
                filSet.add(e.getChartsPath());
            }
            if(!hashSet.contains(e.getBomPath())){
                filSet.add(e.getBomPath());
            }
            if(!hashSet.contains(e.getNetPath())){
                filSet.add(e.getNetPath());
            }
            if(!hashSet.contains(e.getDesignatorsPath())){
                filSet.add(e.getDesignatorsPath());
            }
        }
        filSet.remove("");
        JSONArray jsonArray = new JSONArray();
        jsonArray.addAll(filSet);
        Long userId = tokenService.getLoginUser().getUserid();
        redisService.setCacheObject(Constant.CIRCUIT_CHECK_DOCUMENT_LIBRARY+userId, jsonArray, 2L, TimeUnit.HOURS);
        return jsonArray;
    }

    public void getBucketFliesPath(MinioClient minioClient,Result<Item> dir,String bucketName,Set<String> hashSet){

        try {
            if (!dir.get().isDir()) {
                hashSet.add(bucketName+"/"+dir.get().objectName());
                return;
            }
            Iterable<Result<Item>> files = minioClient.listObjects(ListObjectsArgs.builder()
                    .prefix(dir.get().objectName())
                    .bucket(bucketName)
                    .build());
            for (Result<Item> file : files) {
                getBucketFliesPath(minioClient,file,bucketName,hashSet);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public JSONArray checkDocumentLibraryDownload(){
        Long userId = tokenService.getLoginUser().getUserid();
        return redisService.getCacheObject(Constant.CIRCUIT_CHECK_DOCUMENT_LIBRARY+userId);
    }
}
